(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.VPlayer = factory());
}(this, (function () { 'use strict';

    /*! *****************************************************************************
    Copyright (c) Microsoft Corporation.

    Permission to use, copy, modify, and/or distribute this software for any
    purpose with or without fee is hereby granted.

    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
    PERFORMANCE OF THIS SOFTWARE.
    ***************************************************************************** */
    /* global Reflect, Promise */

    var extendStatics = function(d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };

    function __extends(d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    }

    /**
     * 判断是否为m3u8
     * @param {string} url
     */
    function isM3U8(url) {
        if (typeof url !== 'string') {
            throw new Error('The video url should be string type');
        }
        return /\.m3u8$/.test(url);
    }
    /**
     * 判断是否为mp4
     * @param {string} url
     */
    function isMP4(url) {
        if (typeof url !== 'string') {
            throw new Error('The video url should be string type');
        }
        url = url.toLowerCase();
        return /\.mp4$/.test(url);
    }
    function hasClass(obj, cls) {
        return obj.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
    }
    function addClass(obj, cls) {
        if (!hasClass(obj, cls))
            obj.className += " " + cls;
    }
    function removeClass(obj, cls) {
        if (hasClass(obj, cls)) {
            var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
            obj.className = obj.className.replace(reg, ' ');
        }
    }
    function findElPosition(el) {
        var box;
        if (el.getBoundingClientRect && el.parentNode) {
            box = el.getBoundingClientRect();
        }
        if (!box) {
            return {
                left: 0,
                top: 0,
            };
        }
        var docEl = document.documentElement;
        var body = document.body;
        var clientLeft = docEl.clientLeft || body.clientLeft || 0;
        var scrollLeft = window.pageXOffset || body.scrollLeft;
        var left = box.left + scrollLeft - clientLeft;
        var clientTop = docEl.clientTop || body.clientTop || 0;
        var scrollTop = window.pageYOffset || body.scrollTop;
        var top = box.top + scrollTop - clientTop;
        // Android sometimes returns slightly off decimal values, so need to round
        return {
            left: Math.round(left),
            top: Math.round(top),
        };
    }
    /**
     * 格式化时间为分钟形式00:00
     * @param {number} time
     */
    function formatTime(time) {
        time = time < 0 ? 0 : time;
        var s = pad(Math.floor(time % 60));
        var m = pad(Math.floor(time / 60));
        return m + ":" + s;
    }
    function pad(num, n) {
        n = isUndefined(n) ? 2 : +n;
        var result = String(num);
        while (result.length < n) {
            result = '0' + num;
        }
        return result;
    }
    /**
    * 是否为undefinded
    * @param {any} obj
    */
    function isUndefined(obj) {
        return void 0 === obj;
    }
    /**
     * 全屏
     * @param {dom} elem
     */
    function requestFullscreen(elem) {
        if (elem.requestFullscreen) {
            elem.requestFullscreen();
        }
        else if (elem.webkitRequestFullScreen) {
            // 对 Chrome 特殊处理，
            // 参数 Element.ALLOW_KEYBOARD_INPUT 使全屏状态中可以键盘输入。
            if (window.navigator.userAgent.toUpperCase().indexOf('CHROME') >= 0) {
                elem.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
            }
            // Safari 浏览器中，如果方法内有参数，则 Fullscreen 功能不可用。
            else {
                elem.webkitRequestFullScreen();
            }
        }
        else if (elem.mozRequestFullScreen) {
            elem.mozRequestFullScreen();
        }
    }
    /**
     * 取消全屏
     */
    function exitFullscreen() {
        var dom = document;
        if (dom.exitFullscreen) {
            dom.exitFullscreen();
        }
        else if (dom.webkitCancelFullScreen) {
            dom.webkitCancelFullScreen();
        }
        else if (dom.mozCancelFullScreen) {
            dom.mozCancelFullScreen();
        }
    }
    /**
     * 获取距离文档顶部的距离
     * @param e
     */
    function getTop(e) {
        var offset = e.offsetTop;
        if (e.offsetParent != null)
            offset += getTop(e.offsetParent);
        return offset;
    }

    var Video = /** @class */ (function () {
        function Video(options) {
            this.videoWrapper = options.el || document.body;
            this.videoWrapper.classList.add('vp-container');
            this.createVideo();
            if (options.url)
                this.setUrl(options.url);
            this.$addEvent();
        }
        Video.prototype.createVideo = function () {
            this.video = document.createElement('video');
            this.video.setAttribute('crossorigin', 'anonymous');
            this.video.setAttribute('id', 'video-player');
            this.video.setAttribute('playsinline', 'true');
            this.video.setAttribute('x5-video-player-fullscreen', 'true');
            this.video.setAttribute('x5-video-player-type', 'h5');
            // this.video.setAttribute('poster', 'https://i.loli.net/2020/10/31/no5BSXl8DWITKGZ.jpg') 
            this.video.className = 'vp-video';
            this.video.volume = 0.7;
        };
        Video.prototype.setUrl = function (url) {
            if (isM3U8(url)) {
                if (window.Hls && window.Hls.isSupported()) {
                    var hls = new window.Hls();
                    hls.loadSource(url);
                    hls.attachMedia(this.video);
                }
                else {
                    throw new Error('Please load the hls.js before video init');
                }
            }
            else if (isMP4(url)) {
                this.video.src = url;
            }
            else {
                throw new Error('UnSupport video url');
            }
        };
        Object.defineProperty(Video.prototype, "currentTime", {
            get: function () {
                return this.video && this.video.currentTime || 0;
            },
            set: function (time) {
                this.video && (this.video.currentTime = time);
            },
            enumerable: false,
            configurable: true
        });
        Object.defineProperty(Video.prototype, "volume", {
            get: function () {
                return this.video && this.video.volume || 0;
            },
            set: function (volume) {
                this.video && (this.video.volume = volume);
            },
            enumerable: false,
            configurable: true
        });
        Object.defineProperty(Video.prototype, "duration", {
            get: function () {
                return this.video && this.video.duration || 0;
            },
            enumerable: false,
            configurable: true
        });
        Video.prototype.play = function (url) {
            if (!url) {
                this.video && this.video.play();
            }
            else {
                this.setUrl(url);
            }
        };
        Video.prototype.pause = function () {
            this.video && this.video.pause();
        };
        Video.prototype.toggle = function () {
            if (this.video.paused === true)
                this.play();
            else if (this.video.paused === false)
                this.pause();
        };
        Video.prototype.$addEvent = function () {
            var _this = this;
            var eventArr = ['play', 'pause', 'loadstart', 'loadeddata', 'progress', 'canplay', 'timeupdate', 'ended'];
            eventArr.forEach(function (item) {
                _this.video.addEventListener(item, function () {
                    _this['$on' + item]();
                });
            });
        };
        Video.prototype.$onplay = function () { };
        Video.prototype.$onpause = function () { };
        Video.prototype.$onloadstart = function () { };
        Video.prototype.$onloadeddata = function () { };
        Video.prototype.$onprogress = function () { };
        Video.prototype.$oncanplay = function () { };
        Video.prototype.$ontimeupdate = function () { };
        Video.prototype.$onended = function () { };
        return Video;
    }());

    // 暂停按钮
    function createPauseButton() {
        var el = document.createElement('span');
        el.className = 'vp-container-center-button vp-container-pause-button';
        el.innerHTML = '&#xe607;';
        return el;
    }
    // 加载中
    function createLoadingButton() {
        var el = document.createElement('span');
        el.className = 'vp-container-center-button vp-container-loading-button';
        el.innerHTML = '&#xe60d;';
        return el;
    }
    // 控制条
    function createControlBar() {
        var el = document.createElement('div');
        el.className = 'vp-control-bar';
        var playButton = document.createElement('span');
        playButton.className = 'vp-control-bar_playbtn';
        var timeGroup = document.createElement('span');
        timeGroup.className = 'vp-control-bar_timegroup';
        timeGroup.innerHTML =
            '<span class="vp-control-bar_timegroup_currenttime">0:00</span>&nbsp;/&nbsp;<span class="vp-control-bar_timegroup_duration">0:00</span>';
        var progress = document.createElement('span');
        progress.className = 'vp-control-bar_progress';
        progress.innerHTML = '<div class="vp-control-bar_progress_inner"><div class="vp-progress-loaded"></div><div class="vp-progress-slide"></div></div>';
        var fullScreenBtn = document.createElement('span');
        fullScreenBtn.className = 'vp-control-bar_full-screen-btn';
        var rateButton = document.createElement('span');
        rateButton.className = 'vp-control-bar_rate-select';
        rateButton.innerHTML = "<div class=\"vp-now-rate\">1.0x</div>";
        var volumeBar = document.createElement('span');
        volumeBar.className = 'vp-control-bar_volume-bar';
        volumeBar.innerHTML = "<div class=\"vp-menu-content\">\n        <div class=\"vp-volume-bar\"\n        ><div class=\"vp-volume-level\">\n        </div>\n        <div class=\"vp-volume-volume-bar-text\">70</div>\n        </div>\n    </div>";
        [playButton, timeGroup, progress, rateButton, volumeBar, fullScreenBtn].forEach(function (element) {
            el.appendChild(element);
        });
        return el;
    }

    // 重写播放器的全屏／取消全屏方法，重新指定全屏的元素（而不只是播放器本身）
    // https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API
    var FullscreenApi = {};
    // browser API methods
    var apiMap = [
        [
            'requestFullscreen',
            'exitFullscreen',
            'fullscreenElement',
            'fullscreenEnabled',
            'fullscreenchange',
            'fullscreenerror'
        ],
        // WebKit
        [
            'webkitRequestFullscreen',
            'webkitExitFullscreen',
            'webkitFullscreenElement',
            'webkitFullscreenEnabled',
            'webkitfullscreenchange',
            'webkitfullscreenerror'
        ],
        // Old WebKit (Safari 5.1)
        [
            'webkitRequestFullScreen',
            'webkitCancelFullScreen',
            'webkitCurrentFullScreenElement',
            'webkitCancelFullScreen',
            'webkitfullscreenchange',
            'webkitfullscreenerror'
        ],
        // Mozilla
        [
            'mozRequestFullScreen',
            'mozCancelFullScreen',
            'mozFullScreenElement',
            'mozFullScreenEnabled',
            'mozfullscreenchange',
            'mozfullscreenerror'
        ],
        // Microsoft
        [
            'msRequestFullscreen',
            'msExitFullscreen',
            'msFullscreenElement',
            'msFullscreenEnabled',
            'MSFullscreenChange',
            'MSFullscreenError'
        ]
    ];
    var specApi = apiMap[0];
    var browserApi;
    // determine the supported set of functions
    for (var i = 0; i < apiMap.length; i++) {
        // check for exitFullscreen function
        if (apiMap[i][1] in document) {
            browserApi = apiMap[i];
            break;
        }
    }
    // map the browser API names to the spec API names
    if (browserApi) {
        for (var i = 0; i < browserApi.length; i++) {
            FullscreenApi[specApi[i]] = browserApi[i];
        }
    }

    var rateGroup = ['0.75', '1.0', '1.25', '1.5', '1.75', '2.0'];
    var nowRateIndex = 1;
    var EventManage = /** @class */ (function () {
        function EventManage(player) {
            this.ifFullScreen = false;
            this.progressDragStart = false;
            this.volumeDragStart = false;
            this.isProgressDragging = false;
            this.isVolumeDragging = false;
            this.tempVolume = 0.7;
            this.player = player;
            this.playerEvent();
            this.progressEvent();
            this.controlBarEvent();
            this.volumeEvent();
            this.windowEvent();
        }
        // 添加监听事件
        EventManage.prototype.addEvent = function (dom, name, callback) {
            var cbk = function (event) {
                callback(event);
            };
            dom.addEventListener(name, cbk, false);
            EventManage.eventList.push({
                callback: cbk,
                name: name,
                dom: dom
            });
        };
        // 移除所有事件
        EventManage.prototype.moveAllEvent = function () {
            EventManage.eventList.forEach(function (item) {
                item.dom.removeEventListener(item.name, item.callback);
            });
        };
        EventManage.prototype.playerEvent = function () {
            var player = this.player;
            this.addEvent(player.videoWrapper, 'click', function () {
                player.toggle();
            });
            this.addEvent(player.videoWrapper, 'mousemove', function () {
                player.onContainerOver();
            });
        };
        EventManage.prototype.progressEvent = function () {
            var _this = this;
            var progress = document.querySelector('.vp-control-bar_progress_inner'), slide = document.querySelector('.vp-progress-slide'), player = this.player, progressWrapper = document.querySelector('.vp-control-bar_progress');
            this.addEvent(progress, 'mousedown', function (event) {
                _this.progressDragStart = true;
                addClass(player.videoWrapper, 'vp-video-loadstart');
                var left = event.pageX - findElPosition(progress).left;
                var progressWidth = progress.offsetWidth;
                var percent = left / progressWidth * 100;
                slide.setAttribute('style', "width: " + percent + "%");
                var duration = player.duration;
                var currentTime = duration * percent / 100 || 0;
                player.seekTo(currentTime);
            });
            this.addEvent(progressWrapper, 'mousemove', function (event) {
                if (_this.progressDragStart) {
                    addClass(player.videoWrapper, 'vp-video-loadstart');
                    var left = event.pageX - findElPosition(progress).left;
                    var progressWidth = progress.offsetWidth;
                    var percent = left / progressWidth * 100;
                    slide.setAttribute('style', "width: " + percent + "%");
                    var duration = player.duration;
                    var currentTime = duration * percent / 100 || 0;
                    if (!_this.isProgressDragging)
                        _this.isProgressDragging = true;
                    player.seekTo(currentTime);
                }
            });
        };
        EventManage.prototype.controlBarEvent = function () {
            var _this = this;
            var player = this.player;
            var controlBar = document.querySelector('.vp-control-bar');
            this.addEvent(controlBar, 'click', function (event) {
                event.stopPropagation();
            });
            var playBtn = document.querySelector('.vp-control-bar_playbtn');
            this.addEvent(playBtn, 'click', function () {
                player.toggle();
            });
            var fullScreenBtn = document.querySelector('.vp-control-bar_full-screen-btn');
            var nowRateBtn = document.querySelector('.vp-now-rate');
            this.addEvent(fullScreenBtn, 'click', function (event) {
                event.stopPropagation();
                if (_this.ifFullScreen) {
                    exitFullscreen();
                }
                else {
                    requestFullscreen(player.videoWrapper);
                }
            });
            this.addEvent(nowRateBtn, 'click', function (event) {
                event.stopPropagation();
                var nextIndex = nowRateIndex + 1;
                if (nowRateIndex >= rateGroup.length - 1)
                    nextIndex = 0;
                nowRateIndex = nextIndex;
                nowRateBtn.innerText = rateGroup[nowRateIndex] + 'x';
                player.video.playbackRate = Number(rateGroup[nowRateIndex]);
            });
            var videoWrapper = document.getElementById('video-player');
            this.addEvent(videoWrapper, 'x5videoexitfullscreen', function () {
                _this.ifFullScreen = false;
                removeClass(player.videoWrapper, 'vp-container-full-screen');
            });
            this.addEvent(videoWrapper, 'webkitendfullscreen', function () {
                _this.ifFullScreen = false;
                removeClass(player.videoWrapper, 'vp-container-full-screen');
            });
        };
        /**
         * 设置音量
         * @param volume
         */
        EventManage.prototype.setVolume = function (volume) {
            var volumeSlide = document.querySelector('.vp-volume-level'), player = this.player, volumeText = document.querySelector('.vp-volume-volume-bar-text');
            volumeText.innerText = String(Math.round(volume * 100));
            volumeSlide.setAttribute('style', "height: " + volume * 100 + "%");
            player.volume = volume;
        };
        /**
         * 根据事件计算出应设置的音量
         * @param event
         */
        EventManage.prototype.computeVolume = function (event) {
            var volumeBar = document.querySelector('.vp-volume-bar');
            var barHeight = volumeBar.offsetHeight;
            var length = getTop(volumeBar) + barHeight - event.pageY - 1;
            if (length >= barHeight)
                length = barHeight;
            else if (length < 0)
                length = 0;
            return (((length / barHeight) * 100) | 0) / 100;
        };
        /**
         * 音量事件
         */
        EventManage.prototype.volumeEvent = function () {
            var _this = this;
            var volumeBar = document.querySelector('.vp-volume-bar'), player = this.player, volumeWrapper = document.querySelector('.vp-menu-content'), volumeContainer = document.querySelector('.vp-control-bar_volume-bar');
            this.addEvent(volumeBar, 'mousedown', function (event) {
                _this.volumeDragStart = true;
                _this.setVolume(_this.computeVolume(event));
            });
            this.addEvent(volumeWrapper, 'mousemove', function (event) {
                if (_this.volumeDragStart) {
                    if (!_this.isVolumeDragging)
                        _this.isVolumeDragging = true;
                    _this.setVolume(_this.computeVolume(event));
                }
            });
            // 阻止点击事件冒泡
            this.addEvent(volumeWrapper, 'click', function (event) {
                event.stopPropagation();
            });
            // 点击切换是否静音
            this.addEvent(volumeContainer, 'click', function (event) {
                if (player.volume === 0) {
                    _this.setVolume(_this.tempVolume);
                    removeClass(volumeContainer, 'vp-control-bar_volume-bar--muted');
                }
                else {
                    _this.tempVolume = player.volume;
                    addClass(volumeContainer, 'vp-control-bar_volume-bar--muted');
                    _this.setVolume(0);
                }
            });
        };
        /**
         * 窗口事件，包括键盘事件
         */
        EventManage.prototype.windowEvent = function () {
            var _this = this;
            var player = this.player;
            this.addEvent(document, 'mouseup', function () {
                _this.progressDragStart = false;
                _this.isProgressDragging = false;
                _this.volumeDragStart = false;
                _this.isVolumeDragging = false;
            });
            this.addEvent(document, FullscreenApi['fullscreenchange'], function () {
                var isFullscreen = !!document[FullscreenApi['fullscreenElement']];
                if (isFullscreen) {
                    _this.ifFullScreen = true;
                    addClass(player.videoWrapper, 'vp-container-full-screen');
                }
                else {
                    _this.ifFullScreen = false;
                    removeClass(player.videoWrapper, 'vp-container-full-screen');
                }
            });
            this.addEvent(window, 'keydown', function (e) {
                var step = 20;
                switch (e.keyCode) {
                    case 37:
                        player.rewind(step);
                        break;
                    case 39:
                        player.forward(step);
                        break;
                    case 32:
                        e.preventDefault(); // 防止空格触发按钮点击事件
                        player.toggle();
                        break;
                    case 38:
                        _this.setVolume(player.volumeUp());
                        break;
                    case 40:
                        _this.setVolume(player.volumeDown());
                        break;
                }
            });
        };
        EventManage.eventList = [];
        return EventManage;
    }());

    var VPlayer = /** @class */ (function (_super) {
        __extends(VPlayer, _super);
        function VPlayer(options) {
            var _this = _super.call(this, options) || this;
            // 往 wrapper 里装入各个物料
            _this.videoWrapper.appendChild(_this.video);
            _this.videoWrapper.appendChild(createPauseButton());
            _this.videoWrapper.appendChild(createLoadingButton());
            _this.videoWrapper.appendChild(createControlBar());
            var eventManage = new EventManage(_this);
            _this.destory = function () {
                eventManage.moveAllEvent();
                _this.videoWrapper.remove();
            };
            return _this;
        }
        VPlayer.prototype.onContainerOver = function () {
            var _this = this;
            window.clearTimeout(this.timer);
            addClass(this.videoWrapper, 'vp-container-over');
            this.timer = window.setTimeout(function () {
                removeClass(_this.videoWrapper, 'vp-container-over');
            }, 3000);
        };
        VPlayer.prototype.setCurrentTime = function (time) {
            this.video.currentTime = time;
        };
        VPlayer.prototype.seekTo = function (time) {
            this.currentTime = time;
            this.updateBuffered();
        };
        VPlayer.prototype.$onplay = function () {
            addClass(this.videoWrapper, 'vp-video-playing');
            removeClass(this.videoWrapper, 'vp-video-loadstart');
        };
        VPlayer.prototype.$onpause = function () {
            removeClass(this.videoWrapper, 'vp-video-playing');
        };
        VPlayer.prototype.$onloadstart = function () {
            addClass(this.videoWrapper, 'vp-video-loadstart');
        };
        VPlayer.prototype.$onloadeddata = function () {
            removeClass(this.videoWrapper, 'vp-video-loadstart');
        };
        VPlayer.prototype.$ontimeupdate = function () {
            var slide = document.querySelector('.vp-progress-slide'), current = this.currentTime, duration = this.duration;
            var percent = current / duration * 100;
            slide.setAttribute('style', "width: " + percent + "%");
            document.querySelector('.vp-control-bar_timegroup').innerHTML = "<span>" + formatTime(current) + "</span>&nbsp;/&nbsp;<span class=\"vp-control-bar_timegroup_duration\">" + formatTime(duration) + "</span>";
        };
        VPlayer.prototype.$oncanplay = function () {
            removeClass(this.videoWrapper, 'vp-video-loadstart');
        };
        VPlayer.prototype.updateBuffered = function () {
            var end = 0;
            for (var i = 0; i < this.video.buffered.length; i++) {
                if (this.video.buffered.end(i) > this.video.currentTime) {
                    end = this.video.buffered.end(i);
                    break;
                }
            }
            var bufferedPercent = +((end / this.video.duration) * 100).toFixed(2);
            var progressLoaded = document.querySelector('.vp-progress-loaded');
            progressLoaded.setAttribute('style', "width: " + bufferedPercent + "%");
        };
        VPlayer.prototype.$onprogress = function () {
            this.updateBuffered();
        };
        // 快退
        VPlayer.prototype.rewind = function (step) {
            var video = this.video;
            if (video.currentTime - step > 0) {
                video.currentTime = video.currentTime - step;
            }
            else {
                if (video.currentTime < step) {
                    video.currentTime = 0.01;
                }
            }
        };
        // 快进
        VPlayer.prototype.forward = function (step) {
            var video = this.video;
            if (video.currentTime + step < video.duration) {
                video.currentTime = video.currentTime + step;
            }
            else {
                if (video.currentTime < video.duration - 1) {
                    video.currentTime = video.duration - 1;
                }
            }
        };
        VPlayer.prototype.volumeUp = function () {
            var _a;
            var volume = this.video.volume + 0.1;
            if (volume >= 1)
                this.video.volume = 1;
            else
                this.video.volume = volume;
            return ((_a = this.video) === null || _a === void 0 ? void 0 : _a.volume) || 1;
        };
        VPlayer.prototype.volumeDown = function () {
            var _a;
            var volume = this.video.volume - 0.1;
            if (volume <= 0)
                this.video.volume = 0;
            else
                this.video.volume = volume;
            return ((_a = this.video) === null || _a === void 0 ? void 0 : _a.volume) || 0;
        };
        return VPlayer;
    }(Video));

    return VPlayer;

})));
